/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ddbserver.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import ddbserver.DDBServerView;
import ddbserver.common.ExceptionHandler;
import ddbserver.common.ObjectServer;
import ddbserver.common.ResultType;
import ddbserver.common.SQLResult;
import ddbserver.common.Site;
import ddbserver.connections.SiteManager;
import ddbserver.connections.SocketConnector;
import ddbserver.optimizer.QueryTree;
import ddbserver.optimizer.TreeNode;
import ddbserver.connections.ObjectManager;
import ddbserver.constant.Constant;
import java.sql.ResultSet;
import java.util.Random;
import java.util.Vector;

/**
 *
 * @author Roar
 */
public class AdminUtil extends CommonUtil {

    SiteManager siteManager;
    ObjectManager objectManager;
    PaserUtil paser;
    HashMap siteCommands;
    DatabaseUtil dbUtil;
    List<SQLResult> sqlResultList;
    ResultType finalResult;

    public AdminUtil(SocketConnector socketConnector, DDBServerView mainWindow, String name) {
        super(socketConnector, mainWindow, name);
        this.siteManager = SiteManager.getInstance();
        this.objectManager = ObjectManager.getInstance();
        this.paser = new PaserUtil(new DatabaseUtil(mainWindow.getMySQLConnector()), name);
        this.dbUtil = new DatabaseUtil(mainWindow.getMySQLConnector());
        finalResult = new ResultType();
    }

    private void AdminEcho() {
        mainWindow.setText("admin echo from " + socketConnector.getIP());
        socketConnector.send(name);
    }

    private void AdminCreate() {
        mainWindow.setText("admin create from " + socketConnector.getIP());
        String line = socketConnector.read();
        if (line.equalsIgnoreCase("table")) {
            String tableName = name + "_" + socketConnector.read();
            String sql = "create table " + tableName + "(";
            List<String> colname = new ArrayList<String>();
            List<String> coltype = new ArrayList<String>();
            int cols = Integer.parseInt(socketConnector.read());
            for (int i = 0; i < cols; i++) {
                colname.add(socketConnector.read());
                coltype.add(socketConnector.read());
                sql += colname.get(i) + " " + coltype.get(i);
                if (i == cols - 1) {
                    sql += ");";
                } else {
                    sql += ", ";
                }
            }

            if (mainWindow.getMySQLConnector().executeSQL(sql)) {
            } else {
                socketConnector.send("error");
            }
            socketConnector.send("create ok");
        } else if (line.equalsIgnoreCase("database")) {
            mainWindow.setText("not implament yet");
            socketConnector.send("error");
        } else {
            socketConnector.send("error");
        }
    }

    // LH
    private void AdminDrop(int x) {
        mainWindow.setText("admin does drop query from " + socketConnector.getIP());
        String sql = "";
        String line = "";
        if (x == 0) {
            line = socketConnector.read();
            sql = "DROP DATABASE " + line;
        } else {
            int n = Integer.parseInt(socketConnector.read());
            sql = "DROP TABLE ";
            for (int i = 0; i < n; i++) {
                sql += socketConnector.read();
            }
        }
        if (!mainWindow.getMySQLConnector().executeSQL(sql)) {
            socketConnector.send("error");
        }
    }

    // LH
    private void AdminInsert() {
        mainWindow.setText("admin does insert query from " + socketConnector.getIP());
        String tableName = socketConnector.read();
        String sql = "INSERT INTO temp_" + tableName;
        int len = Integer.parseInt(socketConnector.read());
        String r = "(";
        String v = "VALUES(";
        for (int i = 0; i < len - 1; i++) {
            String line = socketConnector.read();
            String[] tmp = line.split("\\s");
            if (i != len - 1) {
                r = r + tmp[0].trim() + ",";
                v = v + tmp[1].trim() + ",";
                continue;
            }
            r = r + tmp[0].trim();
            v = v + tmp[1].trim();
        }
        String[] tmp = socketConnector.read().split("\\s");
        r = r + tmp[0].trim() + ")";
        v = v + tmp[1].trim() + ")";
        sql = sql + r + " " + v;

        sqlResultList = paser.insertSingleRecord(sql, tableName);
        for (int i = 0; i < sqlResultList.size(); i++) {
            if (name.equals(sqlResultList.get(i).getSiteName())) {
                if (sqlResultList.get(i).getSqlType().equals(Constant.LOCAL_COMMAND_RESULET) && sqlResultList.get(i).getResult().getValuesVector().size() < 1) {
                    continue;
                }
                dbUtil.execute(sqlResultList.get(i));
            } else {
                if (sqlResultList.get(i).getSqlType().equals(Constant.REMOTE_COMMAND_RESULTE) && sqlResultList.get(i).getResult().getValuesVector().size() < 1) {
                    continue;
                }
                this.sendObjectToSite(sqlResultList.get(i), false);
            }
        }
        mainWindow.setText("insert into record successfully");
    }

    private void adminSelect() {
        mainWindow.setText("admin does select query from " + socketConnector.getIP());
        List<String> attributes = new ArrayList<String>();
        List<String> tables = new ArrayList<String>();
        List<String> condition = new ArrayList<String>();
        QueryTree tree = new QueryTree();
        for(int i = 0; i < attributes.size(); i++) {
            tree.addAttribute(attributes.get(i));
        }
        for(int i = 0; i < tables.size(); i++) {
            tree.addTable(tables.get(i));
        }
        for(int i = 0; i < condition.size(); i++) {
            tree.addJoin(condition.get(i));    
        }
        List<String> queryList = tree.getQueryQueue();
        for(int i = 0; i < queryList.size(); i++) {
            SQLResult sqlResult = new SQLResult(name, queryList.get(i), Constant.REMOTE_COMMAND_RESULTE);
            dbUtil.execute(sqlResult);
        }
        finalResult = new ResultType();
        finalResult = this.generateFinalResult();
        mainWindow.setText("select successfully");
    }


    // LH
    private void adminDelete() {
        mainWindow.setText("admin delete from " + socketConnector.getIP());
        int tableNumber = Integer.parseInt(socketConnector.read());
        String sql = "delete from ";
        List<String> tableList = new ArrayList<String>();
        List<String> conditionList = new ArrayList<String>();

        for (int i = 0; i < tableNumber; i++) {
            String tableName = socketConnector.read();
            if (i != tableNumber - 1) {
                sql = sql + "temp_" + tableName + ",";
            } else {
                sql = sql + "temp_" + tableName + " where ";
            }
            tableList.add(tableName);
        }

        int attrNumber = Integer.parseInt(socketConnector.read());
        for (int i = 0; i < attrNumber; i++) {
            String condition = socketConnector.read();
            if (i != attrNumber - 1) {
                sql = sql + condition + " and ";
            } else {
                sql = sql + condition;
            }
            conditionList.add(condition);
        }
        this.emptySQLResultList();
        sqlResultList = paser.deleteSingleRecord(sql, tableList, conditionList);
        for (int i = 0; i < sqlResultList.size(); i++) {
            if (sqlResultList.get(i).getSiteName().equals(name)) {
                dbUtil.execute(sqlResultList.get(i));
            } else {
                this.sendObjectsToSites(sqlResultList.get(i));
            }
        }
        mainWindow.setText(sql);
    }

    //LH
    private void AdminCreateDB() {
        mainWindow.setText("admin create db");
        String dbname = socketConnector.read();
        List<Site> slist = SiteManager.getInstance().getConnectedSite();
        String localhost = DDBServerView.getInstance().getSite();
        String[] address = localhost.split("\\s")[0].split(":", 2);
        String ip = address[0];
        int port = Integer.parseInt(address[1]);
        for (Site site : slist) {
            if (site.getIP().equalsIgnoreCase(ip) && site.getPort() == port) {
                continue;
            }
            site.connect();
            if (site.isConnected()) {
                site.send("admin");
                site.send("createdb");
                site.send(dbname);
            }
        }
    }

    public void AdminImportData() {
        sqlResultList = paser.paserScript(socketConnector);
        String localIP = siteManager.getSiteByName(name).getIP();
        for (String site : siteManager.getSites()) {
            Site clientSite = siteManager.getSite(site);
            if (!clientSite.getIP().equals(localIP)) {
                this.sendCommandsToSites(Constant.DDB_IMPORT, clientSite);
            }
        }
        for (int i = 0; i < sqlResultList.size(); i++) {
            if (sqlResultList.get(i).getSiteName().equals(name)) {
                dbUtil.execute(sqlResultList.get(i));
            } else {
                this.sendObjectsToSites(sqlResultList.get(i));
            }
        }
        this.emptySQLResultList();
        mainWindow.setText("import data successfully");
    }

    public void AdminPaserScript() {
        sqlResultList = paser.paserScript(socketConnector);
        for (int i = 0; i < sqlResultList.size(); i++) {
            if (sqlResultList.get(i).getSiteName().equals(name)) {
                dbUtil.execute(sqlResultList.get(i));
                mainWindow.setText(sqlResultList.get(i).getSql());
            } else {
                this.sendObjectsToSites(sqlResultList.get(i));
            }
        }
        this.emptySQLResultList();
        mainWindow.setText("successfully create tables!");
    }

    public void run() {
        String str;
        sqlResultList = new ArrayList<SQLResult>();
        try {
            if ((str = socketConnector.read()) != null) {
                if (str.equalsIgnoreCase("echo")) {
                    AdminEcho();
                } else if (str.equalsIgnoreCase("create")) {
                    AdminCreate();
                } else if (str.equalsIgnoreCase("dropdb")) {
                    AdminDrop(0);
                } else if (str.equalsIgnoreCase("droptable")) {
                    AdminDrop(1);
                } else if (str.equalsIgnoreCase("insert")) {
                    mainWindow.setText("insert record");
                    AdminInsert();
                } else if (str.equalsIgnoreCase("delete")) {
                    adminDelete();
                } else if (str.equalsIgnoreCase("select")) {
                    adminSelect();
                } else if (str.equalsIgnoreCase("importData")) {
                    AdminImportData();
                } else if (str.equalsIgnoreCase("ExecuteScript")) {
                    AdminPaserScript();
                }
            }
        } catch (Exception e) {
            ExceptionHandler.handleExcptin(e);
        }
    }

    public void sendObjectsToSites(SQLResult sqlResult) {
        Site site = siteManager.getSiteByName(sqlResult.getSiteName());
        site.sendObject(sqlResult);
    }

    public void sendObjectToSite(SQLResult sqlResult, boolean flag) {
        Site site = siteManager.getSiteByName(sqlResult.getSiteName());
        String key = objectManager.addObject(sqlResult);
        site.sendObject(key, flag);
    }

    public SQLResult sendObjectAndWaitResult(SQLResult sqlResult) {
        Site site = siteManager.getSiteByName(sqlResult.getSiteName());
        site.newSession();
        site.send("client");
        site.send("queryWaitResult");
        site.send(name);
        Random rand = new Random();
        int objectPort = 10000 + rand.nextInt(10000);
        site.send("" + objectPort);
        try {
            ObjectServer observer = new ObjectServer(objectPort, sqlResult);
            String port = site.read();
            SQLResult relvalue = (SQLResult) site.reciveObject(Integer.parseInt(port));
            return relvalue;
        } catch (Exception e) {
            ExceptionHandler.handleExcptin(e);
            return null;
        }
    }

    public void sendResultToAdmin() {
        Random rand = new Random();
        int portToAdmin = 10002 + rand.nextInt(10000);
        socketConnector.send("" + portToAdmin);
        new ObjectServer(portToAdmin, finalResult);
    }

    public void sendCommandsToSites(String command, Site site) {
        site.newSession();
        site.send("client");
        site.send(command);
    }

    public void emptySQLResultList() {
        int count = 0;
        if (sqlResultList != null) {
            count = sqlResultList.size();
            for (int i = 0; i < count; i++) {
                sqlResultList.remove(0);
            }
        }
    }

    public ResultType generateFinalResult() {
        Vector tempVector = new Vector();
        int sameAttrCount = 0;
        return null;
    }
    
    public TreeNode getCase(int index) {
		TreeNode root = new TreeNode();
		switch(index) {
		case 0:
			root.setType(Constant.DDB_LABEL_UNION);
			TreeNode[] sons = new TreeNode[3];
			for(int i=0;i<3;i++) {
				sons[i] = new TreeNode();
				sons[i].setType(Constant.DDB_LABEL_PROJECT);
				sons[i].addAttribute("id");
				sons[i].addAttribute("name");
				sons[i].addAttribute("gender");
				sons[i].addAttribute("rank");
				root.addChild(sons[i]);
				sons[i].setParent(root);
			}
			for(int i=0;i<3;i++) {
				TreeNode site = new TreeNode();
				site.setParent(sons[i]);
				site.setType(Constant.DDB_LABEL_SITE);
				site.setName("Customer."+(i+1));
				sons[i].addChild(site);
			}
			break;
		case 1:
			root.setType(Constant.DDB_LABEL_PROJECT);
			root.addAttribute("Product.name");
			TreeNode son = new TreeNode();
			son.setName("Prodct.1");
			son.setType(Constant.DDB_LABEL_SITE);
			son.setParent(root);
			root.addChild(son);
			break;
		case 2:
			root.setType(Constant.DDB_LABEL_UNION);
			TreeNode[] pjs = new TreeNode[2];
			for(int i=0;i<2;i++) {
				pjs[i] = new TreeNode();
				pjs[i].setType(Constant.DDB_LABEL_PROJECT);
				pjs[i].addAttribute("name");
				pjs[i].setParent(root);
				root.addChild(pjs[i]);
			}
			TreeNode[] joins = new TreeNode[2];
			for(int i=0;i<2;i++) {
				joins[i] = new TreeNode();
				joins[i].setType(Constant.DDB_LABEL_JOIN);
				joins[i].addPredicate("id");
				joins[i].setName("Product");
				joins[i].setParent(pjs[i]);
				pjs[i].addChild(joins[i]);
			}
			TreeNode[] sites = new TreeNode[4];
			for(int i=0;i<4;i++) {
				sites[i] = new TreeNode();
				sites[i].setType(Constant.DDB_LABEL_SITE);
			}
			sites[0].setName("Product.1");
			sites[1].setName("Product.2.1");
			sites[2].setName("Product.2.2");
			sites[3].setName("Product.1");
			sites[0].setParent(joins[0]);
			sites[1].setParent(joins[0]);
			joins[0].addChild(sites[0]);
			joins[0].addChild(sites[1]);
			sites[2].setParent(joins[1]);
			sites[3].setParent(joins[1]);
			joins[1].addChild(sites[2]);
			joins[1].addChild(sites[3]);
			break;
		case 3:root.setType(Constant.DDB_LABEL_UNION);
			sites = new TreeNode[4];
			for(int i=0;i<4;i++) {
				sites[i] = new TreeNode();
				sites[i].setType(Constant.DDB_LABEL_SITE);
				sites[i].setName("Purchase."+(i+1));
			}
			TreeNode[] selects = new TreeNode[4];
			for(int i=0;i<4;i++) {
				selects[i] = new TreeNode();
				selects[i].setType(Constant.DDB_LABEL_SELECT);
				selects[i].addPredicate("number<=3");
				selects[i].addChild(sites[i]);
				sites[i].setParent(selects[i]);
			}
			pjs = new TreeNode[4];
			for(int i=0;i<4;i++) {
				pjs[i] = new TreeNode();
				pjs[i].setType(Constant.DDB_LABEL_PROJECT);
				pjs[i].addAttribute("customer_id");
				pjs[i].addAttribute("number");
				pjs[i].addChild(selects[i]);
				selects[i].setParent(pjs[i]);
			}	
			for(int i=0;i<4;i++) {
				root.addChild(pjs[i]);
				pjs[i].setParent(root);
			}
			break;
		case 4:
			break;
		case 5:
			break;
		}
		return root;
	}
}
